home *** CD-ROM | disk | FTP | other *** search
/ Just Call Me Internet / Just Call Me Internet.iso / prog / atari / c / nos042_s / ipfilter.c < prev    next >
C/C++ Source or Header  |  1994-09-16  |  13KB  |  647 lines

  1. /*
  2.  *   Packet filtering code for KA9Q.
  3.  *
  4.  *   Copyright 1992 David F. Mischler
  5.  *   This code may be freely distributed as long as this copyright
  6.  *   notice is preserved.
  7.  */
  8.  
  9. /****************************************************************************
  10. *    $Id: ipfilter.c 1.3 94/01/04 14:09:32 ROOT_DOS Exp $
  11. *    14 Jun 93    1.2        GT    Fix warnings.
  12. *    07 Nov 93    1.3        GT    Conditional compilation.
  13. *
  14. *    ATARI Version by David Nash - dnash@chaos.demon.co.uk
  15. *
  16. *  conditionally include "mbuf.h"
  17. *
  18. ****************************************************************************/
  19.  
  20. #include <limits.h>
  21. #include "config.h"
  22.  
  23. #ifdef FILTER
  24.  
  25. #ifndef _MBUF_H
  26. #include "mbuf.h"
  27. #endif
  28.  
  29. #ifndef _FILTER_H
  30. #include "filter.h"
  31. #endif
  32.  
  33. #ifndef _IFACE_H
  34. #include "iface.h"
  35. #endif
  36.  
  37. #ifndef _ICMP_H
  38. #include "icmp.h"
  39. #endif
  40.  
  41. #ifndef _IP_H
  42. #include "ip.h"
  43. #endif
  44.  
  45. #ifndef _NETUSER_H
  46. #include "netuser.h"
  47. #endif
  48.  
  49. #include    "socket.h"
  50.  
  51. #define SDWIDTH 21    /* Width of a displayed source or destination */
  52.  
  53. /*
  54.  *   Information for TCP header kludges.
  55.  */
  56. #define CODEBITS_ACK    16
  57. #define CODEBITS_OFFSET 13
  58. #define CODEBITS_SYN    2
  59. #define SRC_PORT_OFFSET 0    /* TCP & UDP */
  60. #define DST_PORT_OFFSET 2    /* TCP & UDP */
  61.  
  62.  
  63. /*
  64.  *   Function to return a non-zero value if an IP packet
  65.  *   matches a filter entry.
  66.  */
  67. static
  68. int
  69. pkt_ip( struct mbuf *bp, struct ip *ip, struct filter *fp )
  70. {
  71.     /*
  72.      *   If source address doesn't match then get out.
  73.      */
  74.     if ( fp->src.addr == ( ip->source & fp->src.mask ) ) {
  75.         if ( fp->src.exclude )
  76.             return 0;
  77.     }
  78.     else {
  79.         if ( fp->src.exclude == 0 )
  80.             return 0;
  81.     }
  82.  
  83.     /*
  84.      *   If destination address doesn't match then get out.
  85.      */
  86.     if ( fp->dest.addr == ( ip->dest & fp->dest.mask ) ) {
  87.         if ( fp->dest.exclude )
  88.             return 0;
  89.     }
  90.     else {
  91.         if ( fp->dest.exclude == 0 )
  92.             return 0;
  93.     }
  94.  
  95.     return 1;
  96. }
  97.  
  98.  
  99. /*
  100.  *   Function to return a non-zero value if an ICMP packet
  101.  *   matches a filter entry.
  102.  */
  103. static
  104. int
  105. pkt_icmp( struct mbuf *bp, struct ip *ip, struct filter *fp )
  106. {
  107.     /*
  108.      *   Check protocol type.
  109.      */
  110.     if ( ip->protocol != ICMP_PTCL )
  111.         return 0;
  112.  
  113.     /*
  114.      *   Check source & destination addresses.
  115.      */
  116.     return pkt_ip( bp, ip, fp );
  117. }
  118.  
  119. /*
  120.  *   Function to return a non-zero value if an ICMP REDIRECT
  121.  *   packet matches a filter entry.
  122.  */
  123. static
  124. int
  125. pkt_icmprd( struct mbuf *bp, struct ip *ip, struct filter *fp )
  126. {
  127.     /*
  128.      *   Check protocol type and source & destination addresses.
  129.      */
  130.     if ( pkt_icmp( bp, ip, fp ) == 0 )
  131.         return 0;
  132.  
  133.     /*
  134.      *   Check ICMP message type.
  135.      */
  136.     if ( bp->data[ 0 ] == ICMP_REDIRECT )
  137.         return 1;
  138.  
  139.     return 0;
  140. }
  141.  
  142.  
  143. /*
  144.  *   Function to return a non-zero value if an ICMP packet
  145.  *   other than a REDIRECT matches a filter entry.
  146.  */
  147. static
  148. int
  149. pkt_icmpxrd( struct mbuf *bp, struct ip *ip, struct filter *fp )
  150. {
  151.     /*
  152.      *   Check protocol type and source & destination addresses.
  153.      */
  154.     if ( pkt_icmp( bp, ip, fp ) == 0 )
  155.         return 0;
  156.  
  157.     /*
  158.      *   Check ICMP message type.
  159.      */
  160.     if ( bp->data[ 0 ] != ICMP_REDIRECT )
  161.         return 1;
  162.  
  163.     return 0;
  164. }
  165.  
  166.  
  167. /*
  168.  *   Function to return a non-zero value if a TCP packet
  169.  *   matches a filter entry.
  170.  */
  171. static
  172. int
  173. pkt_tcp( struct mbuf *bp, struct ip *ip, struct filter *fp )
  174. {
  175. unsigned short    port;
  176.  
  177.     /*
  178.      *   Check protocol type.
  179.      */
  180.     if ( ip->protocol != TCP_PTCL )
  181.         return 0;
  182.  
  183.     /*
  184.      *   Check source & destination addresses.
  185.      */
  186.     if ( pkt_ip( bp, ip, fp ) == 0 )
  187.         return 0;
  188.  
  189.     /*
  190.      *   Check source port.
  191.      */
  192.     if ( fp->src.port ) {
  193.         port = get16( &bp->data[SRC_PORT_OFFSET] );
  194.         if ( fp->src.port > port || fp->src.hiport < port )
  195.             return 0;
  196.     }
  197.  
  198.     /*
  199.      *   Check destination port.
  200.      */
  201.     if ( fp->dest.port ) {
  202.         port = get16( &bp->data[DST_PORT_OFFSET] );
  203.         if ( fp->dest.port > port || fp->dest.hiport < port )
  204.             return 0;
  205.     }
  206.     return 1;
  207. }
  208.  
  209.  
  210. /*
  211.  *   Function to return a non-zero value if a TCP packet
  212.  *   with SYN set and ACK clear matches a filter entry.
  213.  */
  214. static
  215. int
  216. pkt_tcpsyn( struct mbuf *bp, struct ip *ip, struct filter *fp )
  217. {
  218. unsigned char    codebits;
  219.  
  220.     /*
  221.      *   Check for TCP protocol type and matching addresses.
  222.      */
  223.     if ( pkt_tcp( bp, ip, fp ) == 0 )
  224.         return 0;
  225.  
  226.     /*
  227.      *   Check that SYN is set and ACK is clear.
  228.      */
  229.     codebits = bp->data[ CODEBITS_OFFSET ];
  230.     if ( ( codebits & CODEBITS_SYN ) && ( codebits & CODEBITS_ACK ) == 0 )
  231.         return 1;
  232.  
  233.     return 0;
  234. }
  235.  
  236.  
  237. /*
  238.  *   Function to return a non-zero value if a TCP packet
  239.  *   with SYN clear or ACK set matches a filter entry.
  240.  */
  241. static
  242. int
  243. pkt_tcpxsyn( struct mbuf *bp, struct ip *ip, struct filter *fp )
  244. {
  245. unsigned char    codebits;
  246.  
  247.     /*
  248.      *   Check for TCP protocol type and matching addresses.
  249.      */
  250.     if ( pkt_tcp( bp, ip, fp ) == 0 )
  251.         return 0;
  252.  
  253.     /*
  254.      *   Check that SYN is clear or ACK is set.
  255.      */
  256.     codebits = bp->data[ CODEBITS_OFFSET ];
  257.     if ( ( codebits & CODEBITS_SYN ) == 0 || ( codebits & CODEBITS_ACK ) )
  258.         return 1;
  259.  
  260.     return 0;
  261. }
  262.  
  263.  
  264. /*
  265.  *   Function to return a non-zero value if a UDP packet
  266.  *   matches a filter entry.
  267.  */
  268. static
  269. int
  270. pkt_udp( struct mbuf *bp, struct ip *ip, struct filter *fp )
  271. {
  272. unsigned short    port;
  273.  
  274.     /*
  275.      *   Check protocol type.
  276.      */
  277.     if ( ip->protocol != UDP_PTCL )
  278.         return 0;
  279.  
  280.     /*
  281.      *   Check source & destination addresses.
  282.      */
  283.     if ( pkt_ip( bp, ip, fp ) == 0 )
  284.         return 0;
  285.  
  286.     /*
  287.      *   Check source port.
  288.      */
  289.     if ( fp->src.port ) {
  290.         port = get16( &bp->data[SRC_PORT_OFFSET] );
  291.         if ( fp->src.port > port || fp->src.hiport < port )
  292.             return 0;
  293.     }
  294.  
  295.     /*
  296.      *   Check destination port.
  297.      */
  298.     if ( fp->dest.port ) {
  299.         port = get16( &bp->data[DST_PORT_OFFSET] );
  300.         if ( fp->dest.port > port || fp->dest.hiport < port )
  301.             return 0;
  302.     }
  303.     return 1;
  304. }
  305.  
  306.  
  307. /*
  308.  *   Table of filter actions (indexes must match FILTER_ACTION_*).
  309.  */
  310. static char *Acts[] = {
  311.     "?", "deny", "permit"
  312. };
  313.  
  314. /*
  315.  *   Table of packet type names and matching functions.
  316.  */
  317. static struct {
  318.     char *name;
  319.     int  (*function) __ARGS((struct mbuf *bp, struct ip *ip, struct filter *fp));
  320. } Types[] = {
  321.     { "*",        pkt_ip },        /* Any IP packet    */
  322.     { "icmp",        pkt_icmp },    /* Any ICMP packet    */
  323.     { "icmprd",    pkt_icmprd },    /* ICMP redirect    */
  324.     { "icmpxrd",    pkt_icmpxrd },    /* ICMP except redirect    */
  325.     { "tcp",        pkt_tcp },    /* Any TCP packet    */
  326.     { "tcpsyn",    pkt_tcpsyn },    /* TCP SYN packet    */
  327.     { "tcpxsyn",    pkt_tcpxsyn },    /* TCP except SYN    */
  328.     { "udp",        pkt_udp },    /* Any UDP packet    */
  329.     { NULL,        NULL }
  330. };
  331.  
  332. /*
  333.  *   Function to parse a filter source or destination spec.
  334.  *   A non-zero return value indicates a syntax problem.
  335.  */
  336. static
  337. int
  338. sdparse( char *p, struct filtersd *sdp )
  339. {
  340. char    *addrp;        /* Pointer to address specification    */
  341. char    *bitp;        /* Pointer to bit count            */
  342.  
  343.     sdp->addr = 0L;
  344.     sdp->mask = ~0L;
  345.     sdp->bits = 32;
  346.     sdp->exclude = 0;
  347.     sdp->port = 0;
  348.     sdp->hiport = 0;
  349.  
  350.     /*
  351.      *   Look for '!' in address to specify address exclusion.
  352.      */
  353.     if ( *p == '!' ) {
  354.         p += 1;
  355.         sdp->exclude = 1;
  356.     }
  357.     addrp = p;
  358.  
  359.     /*
  360.      *   Look for '/' in spec to separate number of bits.
  361.      */
  362.     if ((bitp = strchr( p, '/' )) != 0) {
  363.         *bitp++ = '\0';
  364.         p = bitp;
  365.     }
  366.  
  367.     /*
  368.      *   Look for ':' in spec to separate port number.
  369.      */
  370.     if ((p = strchr( p, ':' )) != 0) {
  371.         *p++ = '\0';
  372.         sdp->hiport = sdp->port = atoi( p );
  373.  
  374.         /*
  375.          *   '+' in port spec indicates >= port.
  376.          */
  377.         if ( strchr( p, '+' ) )
  378.             sdp->hiport = USHRT_MAX;
  379.         /*
  380.          *   '-' in port spec indicates port range.
  381.          */
  382.         else if ((p = strchr( p, '-' )) != 0) {
  383.             p += 1;
  384.             sdp->hiport = atoi( p );
  385.         }
  386.         if ( sdp->port > sdp->hiport ) {
  387.             tprintf( "Bad port range\n" );
  388.             return -1;
  389.         }
  390.     }
  391.  
  392.     /*
  393.      *   Evaluate number of bits if necessary.
  394.      */
  395.     if ( bitp )
  396.         sdp->mask <<= ( 32 - (sdp->bits = atoi( bitp )) );
  397.  
  398.     /*
  399.      *   Evaluate host/net address.
  400.      */
  401.     if ( strcmp( "*", addrp ) == 0 ) {
  402.         sdp->bits = 0;
  403.         sdp->mask = 0L;
  404.     }
  405.     else {
  406.         if ( ( sdp->addr = resolve( addrp ) ) == 0 ) {
  407.             tprintf( Badhost, addrp );
  408.             return -1;
  409.         }
  410.     }
  411.  
  412.     sdp->addr &= sdp->mask;
  413.  
  414.     return 0;
  415. }
  416.  
  417. /*
  418.  *   Function to list a source or destination address.
  419.  */
  420. static
  421. void
  422. listaddr( struct filtersd *sdp )
  423. {
  424. int    i = 0;
  425.  
  426.     if ( sdp->exclude ) {
  427.         tputc( '!' );
  428.         i = 1;
  429.     }
  430.  
  431.     if ( sdp->addr == 0L && sdp->bits == 0 ) {
  432.         tputc( '*' );
  433.         i += 1;
  434.     }
  435.     else {
  436.         i += tprintf( "%s", inet_ntoa( sdp->addr ) );
  437.         if ( sdp->bits != 32 )
  438.             i += tprintf( "/%d", sdp->bits );
  439.     }
  440.  
  441.     if ( sdp->port ) {
  442.         i += tprintf( ":%u", sdp->port );
  443.  
  444.         if ( sdp->hiport == USHRT_MAX ) {
  445.             tputc( '+' );
  446.             i += 1;
  447.         }
  448.         else if ( sdp->hiport > sdp->port )
  449.             i += tprintf( "-%u", sdp->hiport );
  450.     }
  451.         
  452.     for ( ; i < SDWIDTH ; i++ )
  453.         tputc( ' ' );
  454. }
  455.  
  456. /*
  457.  *   Function to list a single filter entry.
  458.  */
  459. static
  460. void
  461. listfilter( struct filter *fp, char *iface, char *direct )
  462. {
  463. int    i;
  464.  
  465.     tprintf( "%s %-6s %-3s ", iface, Acts[fp->action], direct );
  466.     for ( i = 0 ; Types[i].name ; i++ ) {
  467.         if ( Types[i].function == fp->type ) {
  468.             tprintf( "%-7s ", Types[i].name );
  469.             break;
  470.         }
  471.     }
  472.  
  473.     listaddr( &fp->src );
  474.     tputc( ' ' );
  475.     listaddr( &fp->dest );
  476.     tprintf( " %lu\n", fp->matches );
  477. }
  478.  
  479. /*
  480.  *  Function to process the IP FILTER command.
  481.  */
  482. int
  483. doipfilter( int argc, char *argv[], void *p )
  484. {
  485. int        action;
  486. struct filter    *fp;    /* Filter entry pointer            */
  487. struct filter    **fpp;    /* Pointer to filter entry pointer    */
  488. struct iface    *ifp;    /* Interface structure pointer        */
  489. int        i;
  490. int        (*type)();
  491. struct filtersd    src,dest;
  492.  
  493.  
  494.     /*
  495.      *   Make sure interface is good.
  496.      */
  497.     if (( ifp = if_lookup( argv[1] ) ) == NULLIF ) {
  498.         tprintf( "Interface \"%s\" unknown\n", argv[1] );
  499.         return 1;
  500.     }
  501.  
  502.     /*
  503.      *   Check action.
  504.      */
  505.     if ( strcmp(argv[2],"delete") == 0 ) {
  506.         /*
  507.          *   Delete entire filter set.
  508.          */
  509.         while ( ifp->infilter ) {
  510.             fp = ifp->infilter;
  511.             ifp->infilter = fp->next;
  512.             free( (char *) fp );
  513.         }
  514.         while ( ifp->outfilter ) {
  515.             fp = ifp->outfilter;
  516.             ifp->outfilter = fp->next;
  517.             free( (char *) fp );
  518.         }
  519.         return 0;
  520.     }
  521.     else if ( strcmp(argv[2],"list") == 0 ) {
  522.         /*
  523.          *   List entire filter set.
  524.          */
  525.         fp = ifp->infilter;
  526.         while ( fp ) {
  527.             listfilter( fp, ifp->name, "in" );
  528.             fp = fp->next;
  529.         }
  530.         fp = ifp->outfilter;
  531.         while ( fp ) {
  532.             listfilter( fp, ifp->name, "out" );
  533.             fp = fp->next;
  534.         }
  535.         return 0;
  536.     }
  537.     else if ( strcmp(argv[2],"deny") == 0 ) {
  538.         action = FILTER_ACTION_DENY;
  539.     }
  540.     else if ( strcmp(argv[2],"permit") == 0 ) {
  541.         action = FILTER_ACTION_PERMIT;
  542.     }
  543.     else {
  544.         tprintf( "Unknown action \"%s\"\n", argv[2] );
  545.         return 2;
  546.     }
  547.  
  548.     /*
  549.      *   Complain if not enough arguments.
  550.      */
  551.     if ( argc < 7 ) {
  552.         tprintf("ip filter <iface> <act> <dir> <type> <src> <dest>\n");
  553.         return -1;
  554.     }
  555.  
  556.     /*
  557.      *   Check direction.
  558.      */
  559.     if ( strncmp(argv[3],"in",2) == 0 ) {
  560.         fpp = &ifp->infilter;
  561.     }
  562.     else if ( strncmp(argv[3],"out",3) == 0 ) {
  563.         fpp = &ifp->outfilter;
  564.     }
  565.     else {
  566.         tprintf( "Unknown direction \"%s\"\n", argv[3] );
  567.         return 3;
  568.     }
  569.  
  570.     /*
  571.      *   Check packet type.
  572.      */
  573.     for ( i = 0 ; Types[i].name ; i++ ) {
  574.         if ( strcmp(argv[4],Types[i].name) == 0 ) {
  575.             type = Types[i].function;
  576.             break;
  577.         }
  578.     }
  579.     if ( Types[i].name == NULL ) {
  580.         tprintf( "Unknown packet type \"%s\"\n", argv[4] );
  581.         return 4;
  582.     }
  583.  
  584.     /*
  585.      *   Parse source specification.
  586.      */
  587.     if ( sdparse( argv[5], &src ) )
  588.         return 5;
  589.  
  590.     /*
  591.      *   Parse destination specification.
  592.      */
  593.     if ( sdparse( argv[6], &dest ) )
  594.         return 6;
  595.  
  596.     /*
  597.      *   Append filter entry to list.
  598.      */
  599.     while ( *fpp )
  600.         fpp = &((*fpp)->next);
  601.  
  602.     *fpp = fp = (struct filter *) callocw( 1, sizeof( struct filter ) );
  603.     fp->action = action;
  604.     fp->type = type;
  605.     fp->src = src;
  606.     fp->dest = dest;
  607.  
  608.     return 0;
  609. }
  610.  
  611. /*
  612.  *  Function to apply a filter specification to a packet.
  613.  *  A non-zero return indicates that the packet should be dropped.
  614.  */
  615. int
  616. ip_filter(struct mbuf *bp, struct ip *ip, struct filter *fp)
  617. {
  618.     /*
  619.      *   Pass all IP fragments except the first.
  620.      */
  621.     if ( ip->offset != 0 )
  622.         return 0;
  623.  
  624.     /*
  625.      *   Walk the filter list until an entry matches the packet.
  626.      */
  627.     for ( ; fp ; fp = fp->next ) {
  628.         /*
  629.          *   If packet doesn't match try the next entry.
  630.          */
  631.         if ( (*fp->type)( bp, ip, fp ) == 0 )
  632.             continue;
  633.  
  634.         fp->matches += 1;
  635.  
  636.         /*
  637.          *   Take specified action.
  638.          */
  639.         if ( fp->action == FILTER_ACTION_PERMIT )
  640.             return 0;
  641.         return -1;
  642.     }
  643.     return 1;    /* Deny all packets not explicitly permitted    */
  644. }
  645.  
  646. #endif     /* ifdef FILTER */
  647.